#include "porting_layer.h"

#include "sys/shm.h"

#define MAX 0
#define MIN 1
#define AVE 2

#define NS_PER_S 1000000000

#define NB_LOOP 1000

int64_t time_diff(struct timespec* t1, struct timespec* t2)
{
    int64_t diff = (t2->tv_sec - t1->tv_sec) * NS_PER_S + (t2->tv_nsec - t1->tv_nsec);
    if (diff < 0)
    {
        diff = -diff;
    }
    return diff;
}

no_main_retval_t main(no_main_argument_t args)
{
    int32_t i;
    sem_t *mutex;
    struct timespec *t;
    int64_t *count;

    //open a file and map it into memory

    // int shm;
    // int fd, i, count = 0, nloop = 10, zero = 0, *ptr;
    // fd = open("log.txt", O_RDWR | O_CREAT, S_IRWXU);
    // write(fd, &zero, sizeof(int));
    // ptr = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    // close(fd);
    // /* create, initialize semaphore */
    // shm = open("sem", O_RDWR | O_CREAT, S_IRWXU);
    // write(shm, &m, sizeof(sem_t));
    // mutex = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED, shm, 0);
    // close(shm);

    int shmut = shmget((key_t)0x1234, sizeof(sem_t), 0777 | IPC_CREAT);
    mutex = (char *)shmat(shmut, NULL, 0);

    int shtime = shmget((key_t)0x2345, sizeof(struct timespec) * 2, 0777 | IPC_CREAT);
    t = (struct timespec *)shmat(shtime, NULL, 0);

    int shint = shmget((key_t)0x3456, sizeof(int) * 3, 0777 | IPC_CREAT);
    count = (int *)shmat(shint, NULL, 0);

    if (sem_init(mutex, 1, 1) < 0)
    {
        perror("semaphore initialization");
        exit(1);
    }

    count[MAX] = 0;
    count[MIN] = INT64_MAX;
    count[AVE] = 0;

    if (fork() == 0)
    { 
        int64_t diff;
        /* child process*/
        for (i = 0; i < NB_LOOP; i++)
        {
            sem_wait(mutex);
            t[0] = no_time_get();
            sem_post(mutex);
            no_task_yield();
            if (i > 0)
            {
                diff = time_diff(t, t+1);
                if (diff > count[MAX]) {
                    count[MAX] = diff;
                }
                if (diff < count[MIN]) {
                    count[MIN] = diff;
                }
                count[AVE] += (diff - count[AVE]) / i;
            }
        }

        no_result_report(count[MAX], count[MIN], count[AVE]);


        exit(0);
    }
    /* back to parent process */
    for (i = 0; i < NB_LOOP; i++)
    {
        sem_wait(mutex);
        t[1] = no_time_get();
        sem_post(mutex);
    }
    exit(0);
}